package com.luhuiguo.cms.server.web.filter;

import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import net.sf.jsr107cache.Cache;

import com.luhuiguo.cms.server.cache.Caches;

public class CachingFilter implements Filter {

    private static final Logger logger = LoggerFactory.getLogger(CachingFilter.class);

    public static final String CACHE_NAME = "webCache";

    // public static final String PAGE_PREFIX = "/page";

    private Cache cache;

    @Override
    public void init(FilterConfig config) throws ServletException {
        cache = Caches.getCache(CACHE_NAME);
    }

    @Override
    public void destroy() {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
            throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        if ("post".equalsIgnoreCase(request.getMethod()) || cache == null) {
            chain.doFilter(servletRequest, servletResponse);
        } else {
            String requestPath = request.getRequestURI();
            String queryString = request.getQueryString();
            if (queryString != null && queryString.length() > 0) {
                requestPath += "?" + queryString;
            }
            String cacheKey = requestPath;

            PageInfo page = null;

            try {
                page = (PageInfo) cache.get(cacheKey);
                if (logger.isDebugEnabled()) {
                    if (page != null) {
                        logger.debug("cache hit " + cacheKey);
                    }
                }
            } catch (Exception e) {
                // type mis-match
                logger.warn(e.getMessage(), e);
            }

            if (page == null) { // on cache content
                ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                GenericResponseWrapper wrapper = new GenericResponseWrapper(response, byteArrayOutputStream);
                chain.doFilter(request, wrapper);
                wrapper.flush();

                page = new PageInfo(wrapper.getStatus(), wrapper.getContentType(), wrapper.getHeaders(), wrapper
                        .getCookies(), byteArrayOutputStream.toByteArray());

                if (page.getStatus() == HttpServletResponse.SC_OK) {
                    cache.put(cacheKey, page);
                    if (logger.isDebugEnabled()) {
                        logger.debug("caching " + cacheKey);
                    }
                }
            }

            response.setStatus(page.getStatus());

            String contentType = page.getContentType();
            if (contentType != null && contentType.length() > 0) {
                response.setContentType(contentType);
            }

            for (Cookie cookie : page.getCookies()) {
                response.addCookie(cookie);
            }

            for (String[] header : page.getResponseHeaders()) {
                response.setHeader(header[0], header[1]);
            }

            response.setContentLength(page.getBody().length);
            BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
            out.write(page.getBody());
            out.flush();
        }

    }

}
